/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package pgentity;

import db.DBContext;
import java.util.HashMap;
import java.util.Map;
import pgentity.pool.EntityFactory;
import share.PGError;
import db.PGKeys;
import share.PGMacro;
import db.RedisKey;
import pgentity.pool.EntityNonBlockingCache;
import share.PGException;

/**
 *
 * @author KieuAnh
 */
@EntityFactory(factorier = "loadGift")
public class GiftCode implements PGEntity
{
    private static final EntityNonBlockingCache<GiftCode> EntityCache;
    static
    {
        EntityCache = EntityNonBlockingCache.make(GiftCode.class,
                500,
                180,   // 3 mins
                new EntityNonBlockingCache.Loader<GiftCode>() {
            @Override
            public GiftCode load(Object[] pars) throws Exception {
                final String code = (String) pars[0];
                
                return loadGift(code);
            }
        });
    }
    private final RedisKey redisKey;
    private final String code;
    
    private String giftTemplateID;
    private int nGiftRemain;
    private String codeGroup;

    private GiftCode(String code) {
        this.code = code;
        this.redisKey = PGKeys.GIFTCODES.getChild(code);
    }
    
    public static GiftCode getGift(String code)
    {
        return EntityCache.get(code);
//        return EntityPool.inst().get(GiftCode.class, code);
    }
    
    public static GiftCode loadGift(String code)
    {
        PGException.Assert(isExist(code),
                PGError.INVALID_GIFT_CODE, "Gift code are invalid or expired");
        
        GiftCode gCode = new GiftCode(code);
        gCode.updateFromDB();
        return gCode;
    }
    
    public static GiftCode newCode(String code, String templID,
            int nGift, int codeExpire)
    {
        PGException.Assert(!isExist(code),
                PGError.EXISTED_GIFT_CODE, "Gift code are already existed");
        
        GiftCode gCode = new GiftCode(code);
        gCode.setGiftTemplateID(templID);
        gCode.setRemain(nGift);
        gCode.saveToDB();
        
        DBContext.Redis().expire(gCode.redisKey, codeExpire);
        
//        EntityPool.inst().put(gCode, GiftCode.class, code);
        EntityCache.put(gCode, code);
        
        return gCode;
    }
    
    
    public static GiftCode newCodeWithGroup(String code, String templID,
            int nGift, int codeExpire, String codeGroup)
    {
        PGException.Assert(!isExist(code),
                PGError.EXISTED_GIFT_CODE, "Gift code are already existed");
        
        GiftCode gCode = new GiftCode(code);
        gCode.setGiftTemplateID(templID);
        gCode.setRemain(nGift);
        gCode.setGroup(codeGroup);
        gCode.saveToDB();
        
        DBContext.Redis().expire(gCode.redisKey, codeExpire);
        
//        EntityPool.inst().put(gCode, GiftCode.class, code);
        EntityCache.remove(code);
        
        return gCode;
    }
    
    public static boolean isExist(String code)
    {
        return DBContext.Redis().exists(PGKeys.GIFTCODES.getChild(code));
    }
    
    @Override
    public void updateFromDB() {
        Map<String, String> data = DBContext.Redis().hgetall(redisKey);
        this.giftTemplateID = data.get(PGMacro.GIFT_TEMPLATE_ID);
        this.nGiftRemain = Integer.parseInt(data.get(PGMacro.REMAINS_GIFT));
        this.codeGroup = data.get(PGMacro.GC_GROUP);
    }

    @Override
    public void saveToDB() 
    {
        Map<String, String> data = new HashMap(2);
        data.put(PGMacro.GIFT_TEMPLATE_ID, this.giftTemplateID);
        data.put(PGMacro.REMAINS_GIFT, String.valueOf(this.nGiftRemain));
        if (isGrouped())
        {
            data.put(PGMacro.GC_GROUP, codeGroup);
        }
        
        DBContext.Redis().hset(redisKey, data);
    }

    public String getCode() {
        return code;
    }

    public String getGiftTemplateID() {
        return giftTemplateID;
    }

    private void setGiftTemplateID(String giftTemplateID) {
        this.giftTemplateID = giftTemplateID;
    }

    public int getRemain() {
        return nGiftRemain;
    }

    private void setRemain(int nGiftRemain) {
        this.nGiftRemain = nGiftRemain;
    }
    
    public int use()
    {
        --this.nGiftRemain;
        return this.nGiftRemain;
    }
    
    public boolean isGrouped()
    {
        return codeGroup != null;
    }

    public String getGroup() {
        return codeGroup;
    }

    private void setGroup(String gcGroup) {
        this.codeGroup = gcGroup;
    }
}
